import CodeGen from '@alilc/lowcode-code-generator';
import { ResultFile, ResultDir } from '@alilc/lowcode-types';
import file1 from './files/menuConfig';

class CodeGeneratorError extends Error {
  readonly detail?: unknown;

  constructor(message: string, detail?: unknown) {
    super(message);
    this.name = this.constructor.name;
    this.detail = detail;
    Object.setPrototypeOf(this, new.target.prototype);
  }
}

function createResultDir(name: string): ResultDir {
  return {
    name,
    dirs: [],
    files: [],
  };
}

function addDirectory(target: ResultDir, dir: ResultDir): void {
  if (target.dirs.findIndex((d) => d.name === dir.name) < 0) {
    target.dirs.push(dir);
  } else {
    throw new CodeGeneratorError(
      `Adding same directory to one directory: ${dir.name} -> ${target.name}`,
    );
  }
}

function addFile(target: ResultDir, file: ResultFile): void {
  const index = target.files.findIndex((f) => f.name === file.name && f.ext === file.ext);
  if (index < 0) {
    target.files.push(file);
  } else {
    // 否则替换
    target.files.splice(index, 1, file);
    // throw new CodeGeneratorError(
    //   `Adding same file to one directory: ${file.name} -> ${target.name}`,
    // );
  }
}

type FuncFileGenerator = () => [string[], ResultFile];

function insertFile(root: ResultDir, path: string[], file: ResultFile) {
  let current: ResultDir = root;
  path.forEach((pathNode) => {
    const dir = current.dirs.find((d) => d.name === pathNode);
    if (dir) {
      current = dir;
    } else {
      const newDir = createResultDir(pathNode);
      addDirectory(current, newDir);
      current = newDir;
    }
  });

  addFile(current, file);
}

function runFileGenerator(root: ResultDir, fun: FuncFileGenerator) {
  try {
    const result = fun();
    const [path, file] = result;
    insertFile(root, path, file);
  } catch (error) {
    throw new Error(`Error: ${typeof fun}`);
  }
}

const { template } = CodeGen.solutionParts.icejs;

const { generateTemplate }: any = template;

template.generateTemplate = (param: any) => {
  const root: any = generateTemplate();
  runFileGenerator(root, () => file1(param));
  return root;
};

export default template;
